我們用簡單的計數器,學習怎麼使用Cubit來存取狀態。
pubspec.yaml
dependencies:
flutter:
sdk: flutter
bloc: ^8.1.0
flutter_bloc: ^8.1.1
CounterCubit 用來儲存 int 狀態,所以繼承於 Cubit<int>
,emit 是用來更改現在有狀態。
lib/counter/cubit/counter_cubit.dart:
class CounterCubit extends Cubit<int> {
CounterCubit(): super(0);
void increment() => emit(state + 1);
void decrement() => emit(state -1);
}
CounterView 用來呈現計數器的畫面,用 BlocBuilder 來呼叫 CounterCubit 的方法與存取它的狀態值。當 state 有變化的時候,BlocBuilder 就會幫我們重繪畫面,不用再需要setState() 來重繪。
context.read() 可以用來呼叫 CounterCubit 的方法。
lib/counter/view/counter_view.dart:
class CounterView extends StatelessWidget {
const CounterView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Scaffold(
appBar: AppBar(
title: const Text('Counter'),
centerTitle: true,
),
body: Center(
child: BlocBuilder<CounterCubit, int>(builder: (context, state) {
return Text('\$state', style: textTheme.headline2);
}),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FloatingActionButton(
key: const Key("counterView_increment_floatingActionButton"),
child: const Icon(Icons.add),
onPressed: () => context.read<CounterCubit>().increment(),
),
const SizedBox(
height: 8,
),
FloatingActionButton(
key: const Key("counterView_decrement_floatingActionButton"),
child: const Icon(Icons.remove),
onPressed: () => context.read<CounterCubit>().decrement(),
)
],
),
);
}
}
輸入 stl+enter,可以快速產生一個繼承於 StatelessWidget 的類別。
可以用一個同名的目錄檔案,可以用來整理 import library,讓程式上面的 import 檔案能夠統一管理。
lib/counter/counter.dart:
export 'cubit/counter_cubit.dart';
CounterPage 是將 CounterCubit 實體化,然後提供給 CounterView。
lib/counter/view/counter_page.dart:
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CounterCubit(), child: const CounterView());
}
}
lib/app.dart
class CounterApp extends MaterialApp {
const CounterApp({super.key}) : super(home: const CounterPage());
}
可以用 CounterObserver 繼承 BlocObserver 來監控應用程式裡,所有的狀態。
lib/counter_observer
class CounterObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
}
lib/main.dart
void main() {
Bloc.observer = CounterObserver();
runApp(const CounterApp());
}
計數器的程式架構將實作層從業務邏輯層分開來,把業務邏輯寫在 CounterCubit 裏面,CounterView 只要負責通知 CounterCubit。CounterCubit 也只要負責將新狀態回傳。